#pragma once
#include<iostream>           
#include<thread>                        
#include<atomic>
#include<queue>
#include<chrono>
#include<functional>

using std::chrono::system_clock;

template <typename T> struct ThreadPool{
  std::queue<T> tasks;
  const std::function<void(T)> worker;
  const static int maxSize = 4;
  const static int maxLiveTime = 3000000;
  const static int maxSpan = 1000000;
  static int span;
  static int curSize;
  static system_clock::time_point pre;
  static std::atomic_flag lock_tasks;
  static std::atomic_flag lock_size;
  static std::atomic_flag lock_time;
  
  ThreadPool(const std::function<void(T)> &w): worker(w){
    lock_tasks.clear();
    lock_size.clear();
    lock_time.clear();
  }
   
  void addTask(T fd){
    while(lock_tasks.test_and_set()) std::this_thread::yield();
    tasks.push(fd);
    lock_tasks.clear();
    workCome();
  }
  
  void workCome(){
    while(lock_time.test_and_set()) std::this_thread::yield();
    auto &&now = system_clock::now();
    auto &&nowSpan = std::chrono::duration_cast<std::chrono::microseconds>(now - pre).count();
    span = nowSpan < span ? nowSpan : span;
    pre = now;
    lock_time.clear();
    while(lock_size.test_and_set()) std::this_thread::yield();
    if(curSize < maxSize){
      ++curSize;
      std::thread(deal, this).detach();
    }
    lock_size.clear();
  }
  
  static void deal(ThreadPool<T> *pool){
    while(true){
      T fd;
      int mark = -1;
      while(lock_time.test_and_set()) std::this_thread::yield();
      int dur = maxSpan < pool->span ? maxSpan : pool->span;
      lock_time.clear();
      while(pool->lock_tasks.test_and_set()){
	if(dur > 0)
	  std::this_thread::sleep_for(std::chrono::microseconds(dur));
      }
      if(pool->tasks.size() > 0){
	mark = 1;
	fd = pool->tasks.front();
	pool->tasks.pop();
      }
      pool->lock_tasks.clear();
      if(mark != -1)
	pool->worker(fd);  //执行
      while(pool->lock_tasks.test_and_set()) std::this_thread::yield();
      if(pool->tasks.size() == 0){
	while(lock_size.test_and_set()) std::this_thread::yield();
	--curSize;
	lock_size.clear();
	pool->lock_tasks.clear();
	break;
      }
      pool->lock_tasks.clear();      
    }
  }
};


template <typename T>
int ThreadPool<T>::span;

template <typename T>
system_clock::time_point ThreadPool<T>::pre = system_clock::now();

template <typename T>
int ThreadPool<T>::curSize = 0;

template <typename T>
std::atomic_flag ThreadPool<T>::lock_tasks = ATOMIC_FLAG_INIT;

template <typename T>
std::atomic_flag ThreadPool<T>::lock_size = ATOMIC_FLAG_INIT;

template <typename T>
std::atomic_flag ThreadPool<T>::lock_time = ATOMIC_FLAG_INIT;
